"""
质量评分API路由
"""
from fastapi import APIRouter, HTTPException, Depends, Query, Path
from typing import List, Dict, Any, Optional
from datetime import datetime, timedelta
import logging
import redis.asyncio as redis
from motor.motor_asyncio import AsyncIOMotorClient

from ..models.quality import (
    ScoreRequest,
    ScoreResponse,
    BatchScoreRequest,
    ScoreResult,
    ScoreHistory,
    QualityMetrics,
    QualityDimension,
    ScenarioType
)
from ..evaluators.quality_scorer import QualityScorer
from ..repositories.quality_repository import QualityRepository
from ..config.quality_weights import WeightConfigManager

logger = logging.getLogger(__name__)

# 创建路由
router = APIRouter(prefix="/api/v1/quality", tags=["quality"])

# 全局实例（生产环境中应通过依赖注入）
scorer: Optional[QualityScorer] = None
weight_manager: Optional[WeightConfigManager] = None
repository: Optional[QualityRepository] = None


def get_scorer() -> QualityScorer:
    """获取评分器实例（延迟初始化）"""
    global scorer
    if scorer is None:
        try:
            scorer = QualityScorer()
            logger.info("QualityScorer initialized successfully")
        except Exception as e:
            logger.error(f"Failed to initialize QualityScorer: {e}")
            raise HTTPException(status_code=500, detail=f"Scorer initialization failed: {str(e)}")
    return scorer


async def get_redis_client() -> Optional[redis.Redis]:
    """获取Redis客户端"""
    try:
        from ..core.config import settings
        redis_url = settings.redis_url if hasattr(settings, 'redis_url') else "redis://localhost:6379"
        client = redis.from_url(redis_url, encoding="utf-8", decode_responses=True)
        await client.ping()
        return client
    except Exception as e:
        logger.warning(f"Redis connection failed: {e}")
        return None


async def get_mongodb_client() -> AsyncIOMotorClient:
    """获取MongoDB客户端"""
    try:
        from ..core.config import settings
        mongodb_url = settings.mongodb_url
        client = AsyncIOMotorClient(mongodb_url)
        return client
    except Exception as e:
        logger.error(f"MongoDB connection failed: {e}")
        raise HTTPException(status_code=500, detail="Database connection failed")


async def get_dependencies():
    """获取依赖"""
    global weight_manager, repository

    if weight_manager is None:
        redis_client = await get_redis_client()
        weight_manager = WeightConfigManager(redis_client)

    if repository is None:
        from ..core.config import settings
        mongodb_client = await get_mongodb_client()
        repository = QualityRepository(mongodb_client, settings.mongodb_database)

    return weight_manager, repository


@router.post("/score", response_model=ScoreResponse)
async def score_content(request: ScoreRequest):
    """
    单文本评分端点
    
    Args:
        request: 评分请求
        
    Returns:
        评分响应
    """
    try:
        # 获取场景类型
        scenario = request.scenario or ScenarioType.GENERAL
        
        # 获取权重配置
        weight_mgr, repo = await get_dependencies()
        weights = await weight_mgr.get_weights(scenario) if request.custom_weights is None else request.custom_weights
        
        # 执行评分
        score_result = await get_scorer().score_content(
            content=request.content,
            scenario=scenario,
            custom_weights=weights
        )
        
        # 保存评分历史
        score_id = None
        if request.content_id and repo:
            history = ScoreHistory(
                content_id=request.content_id,
                content_type=request.content_type,
                content_preview=request.content[:200] if len(request.content) > 200 else request.content,
                scores=score_result,
                metadata={
                    "scenario": scenario.value,
                    "custom_weights": request.custom_weights is not None
                }
            )
            score_id = await repo.save_score(history)
        
        return ScoreResponse(
            score_result=score_result,
            score_id=score_id,
            message="Content scored successfully"
        )
    
    except Exception as e:
        logger.error(f"Error scoring content: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/batch-score")
async def batch_score_content(request: BatchScoreRequest):
    """
    批量评分端点
    
    Args:
        request: 批量评分请求
        
    Returns:
        批量评分结果
    """
    try:
        scenario = request.scenario or ScenarioType.GENERAL
        weight_mgr, repo = await get_dependencies()
        weights = await weight_mgr.get_weights(scenario) if request.custom_weights is None else request.custom_weights
        
        results = []
        score_ids = []
        
        for item in request.contents:
            content = item.get("content", "")
            content_id = item.get("content_id")
            content_type = item.get("content_type", "article")
            
            if not content:
                continue
            
            # 评分
            score_result = await get_scorer().score_content(
                content=content,
                scenario=scenario,
                custom_weights=weights
            )
            
            results.append({
                "content_id": content_id,
                "score_result": score_result.dict()
            })
            
            # 保存历史
            if content_id and repo:
                history = ScoreHistory(
                    content_id=content_id,
                    content_type=content_type,
                    content_preview=content[:200] if len(content) > 200 else content,
                    scores=score_result,
                    metadata={
                        "scenario": scenario.value,
                        "batch_id": datetime.utcnow().isoformat()
                    }
                )
                histories = [history]
                ids = await repo.batch_save_scores(histories)
                score_ids.extend(ids)
        
        return {
            "results": results,
            "total_processed": len(results),
            "score_ids": score_ids,
            "message": "Batch scoring completed"
        }
    
    except Exception as e:
        logger.error(f"Error in batch scoring: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/history/{content_id}")
async def get_score_history(
    content_id: str = Path(..., description="内容ID"),
    limit: int = Query(10, ge=1, le=100, description="返回记录数"),
    skip: int = Query(0, ge=0, description="跳过记录数")
):
    """
    获取评分历史
    
    Args:
        content_id: 内容ID
        limit: 返回记录数
        skip: 跳过记录数
        
    Returns:
        评分历史列表
    """
    try:
        _, repo = await get_dependencies()
        
        if not repo:
            raise HTTPException(status_code=503, detail="Repository service unavailable")
        
        history = await repo.get_score_history(content_id, limit, skip)
        
        return {
            "content_id": content_id,
            "history": [h.dict() for h in history],
            "count": len(history),
            "limit": limit,
            "skip": skip
        }
    
    except Exception as e:
        logger.error(f"Error getting score history: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/statistics")
async def get_score_statistics(
    content_id: Optional[str] = Query(None, description="内容ID"),
    content_type: Optional[str] = Query(None, description="内容类型"),
    days: int = Query(7, ge=1, le=90, description="统计天数")
):
    """
    获取评分统计
    
    Args:
        content_id: 内容ID（可选）
        content_type: 内容类型（可选）
        days: 统计天数
        
    Returns:
        统计信息
    """
    try:
        _, repo = await get_dependencies()
        
        if not repo:
            raise HTTPException(status_code=503, detail="Repository service unavailable")
        
        end_date = datetime.utcnow()
        start_date = end_date - timedelta(days=days)
        
        stats = await repo.get_score_statistics(
            content_id=content_id,
            content_type=content_type,
            start_date=start_date,
            end_date=end_date
        )
        
        return stats.dict()
    
    except Exception as e:
        logger.error(f"Error getting statistics: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.put("/weights")
async def update_weights(
    scenario: ScenarioType = Query(..., description="场景类型"),
    weights: Dict[str, float] = None
):
    """
    更新权重配置
    
    Args:
        scenario: 场景类型
        weights: 新的权重配置
        
    Returns:
        更新结果
    """
    try:
        weight_mgr, _ = await get_dependencies()
        
        if not weight_mgr:
            raise HTTPException(status_code=503, detail="Weight manager service unavailable")
        
        # 验证权重
        if not weight_mgr.validate_weights(weights):
            raise HTTPException(status_code=400, detail="Invalid weights configuration")
        
        # 更新权重
        success = await weight_mgr.set_weights(scenario, weights)
        
        if success:
            return {
                "scenario": scenario.value,
                "weights": weights,
                "message": "Weights updated successfully"
            }
        else:
            raise HTTPException(status_code=500, detail="Failed to update weights")
    
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error updating weights: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/weights/{scenario}")
async def get_weights(scenario: ScenarioType = Path(..., description="场景类型")):
    """
    获取权重配置
    
    Args:
        scenario: 场景类型
        
    Returns:
        权重配置
    """
    try:
        weight_mgr, _ = await get_dependencies()
        
        if not weight_mgr:
            # 返回默认权重
            default_weights = WeightConfigManager.DEFAULT_WEIGHTS.get(
                scenario.value,
                WeightConfigManager.DEFAULT_WEIGHTS[ScenarioType.GENERAL.value]
            )
            return {
                "scenario": scenario.value,
                "weights": default_weights,
                "source": "default"
            }
        
        weights = await weight_mgr.get_weights(scenario)
        
        return {
            "scenario": scenario.value,
            "weights": weights,
            "source": "configured"
        }
    
    except Exception as e:
        logger.error(f"Error getting weights: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/weights/reset/{scenario}")
async def reset_weights(scenario: ScenarioType = Path(..., description="场景类型")):
    """
    重置为默认权重
    
    Args:
        scenario: 场景类型
        
    Returns:
        重置结果
    """
    try:
        weight_mgr, _ = await get_dependencies()
        
        if not weight_mgr:
            raise HTTPException(status_code=503, detail="Weight manager service unavailable")
        
        success = await weight_mgr.reset_weights(scenario)
        
        if success:
            default_weights = weight_mgr.get_default_weights(scenario)
            return {
                "scenario": scenario.value,
                "weights": default_weights,
                "message": "Weights reset to default successfully"
            }
        else:
            raise HTTPException(status_code=500, detail="Failed to reset weights")
    
    except Exception as e:
        logger.error(f"Error resetting weights: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.delete("/cleanup")
async def cleanup_expired_scores(
    days: int = Query(90, ge=1, le=365, description="保留天数")
):
    """
    清理过期评分数据
    
    Args:
        days: 保留天数
        
    Returns:
        清理结果
    """
    try:
        _, repo = await get_dependencies()
        
        if not repo:
            raise HTTPException(status_code=503, detail="Repository service unavailable")
        
        deleted_count = await repo.clean_expired_scores(days)
        
        return {
            "deleted_count": deleted_count,
            "retention_days": days,
            "message": f"Cleaned {deleted_count} expired score records"
        }
    
    except Exception as e:
        logger.error(f"Error cleaning expired scores: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/scenarios")
async def get_scenarios():
    """
    获取所有场景类型
    
    Returns:
        场景类型列表
    """
    scenarios = []
    for scenario in ScenarioType:
        scenarios.append({
            "value": scenario.value,
            "name": scenario.name,
            "description": {
                ScenarioType.NEWS: "新闻类内容",
                ScenarioType.BLOG: "博客类内容",
                ScenarioType.TECHNICAL: "技术文档",
                ScenarioType.CREATIVE: "创意写作",
                ScenarioType.GENERAL: "通用内容"
            }.get(scenario, "")
        })
    
    return {"scenarios": scenarios}


@router.get("/dimensions")
async def get_dimensions():
    """
    获取所有质量维度
    
    Returns:
        质量维度列表
    """
    dimensions = []
    for dim in QualityDimension:
        dimensions.append({
            "value": dim.value,
            "name": dim.name,
            "description": {
                QualityDimension.ORIGINALITY: "原创性 - 内容的独特性和创新性",
                QualityDimension.READABILITY: "可读性 - 文章的流畅度和易读性",
                QualityDimension.INFORMATION_DENSITY: "信息量 - 内容的信息密度和价值",
                QualityDimension.EMOTIONAL_RESONANCE: "情感共鸣 - 内容的感染力和互动性",
                QualityDimension.STRUCTURE_INTEGRITY: "结构完整性 - 文章结构和逻辑连贯性"
            }.get(dim, "")
        })
    
    return {"dimensions": dimensions}


@router.get("/health")
async def health_check():
    """
    健康检查端点
    
    Returns:
        服务状态
    """
    try:
        # 检查各组件状态
        redis_status = "healthy"
        mongo_status = "healthy"
        
        try:
            redis_client = await get_redis_client()
            if redis_client:
                await redis_client.ping()
            else:
                redis_status = "unavailable"
        except:
            redis_status = "unhealthy"
        
        try:
            mongo_client = await get_mongodb_client()
            await mongo_client.admin.command('ping')
        except:
            mongo_status = "unhealthy"
        
        return {
            "status": "healthy" if redis_status == "healthy" and mongo_status == "healthy" else "degraded",
            "service": "quality-scoring",
            "components": {
                "scorer": "ready",
                "redis": redis_status,
                "mongodb": mongo_status
            },
            "timestamp": datetime.utcnow().isoformat()
        }
    
    except Exception as e:
        logger.error(f"Health check failed: {e}")
        return {
            "status": "unhealthy",
            "error": str(e),
            "timestamp": datetime.utcnow().isoformat()
        }